-- dcache wrapper
-- this is provided for a place holder until you do the cache labs
-- until then you should just place this file between your memory stage
-- of your pipeline and your priority mux for main memory.
library ieee;
use ieee.std_logic_1164.all;
use IEEE.NUMERIC_STD.all;
use work.typeDefinitions.all;

entity dcache is
  port(
    clk      : in  std_logic;
    nReset   : in  std_logic;
    halt     : in  std_logic;
    halt_out : out std_logic;

    dMemRead      : in  std_logic;                       -- CPU side
    dMemWrite     : in  std_logic;                       -- CPU side
    dMemWait      : out std_logic;                       -- CPU side
    dMemAddr      : in  std_logic_vector (31 downto 0);  -- CPU side
    dMemDataRead  : out std_logic_vector (31 downto 0);  -- CPU side
    dMemDataWrite : in  std_logic_vector (31 downto 0);  -- CPU side

    adMemRead      : out std_logic;                       -- arbitrator side
    adMemWrite     : out std_logic;                       -- arbitrator side
    adMemWait      : in  std_logic;                       -- arbitrator side
    adMemAddr      : out std_logic_vector (31 downto 0);  -- arbitrator side
    adMemDataRead  : in  std_logic_vector (31 downto 0);  -- arbitrator side
    adMemDataWrite : out std_logic_vector (31 downto 0)   -- arbitrator side
    );

end dcache;

architecture struct of dcache is


  component dcache_ctrl port(
    clk, nReset                : in  std_logic;
    halt                       : in  std_logic;
    -- CPU side
    dmemREN, dmemWEN           : in  std_logic;
    dmemAddr                   : in  std_logic_vector(31 downto 0);
    dmemWriteData              : in  std_logic_vector(31 downto 0);
    dmemReadData               : out std_logic_vector(31 downto 0);
    dmemWait                   : out std_logic;
    -- Arbiter side
    arbREN                     : out std_logic;  -- dcache read request
    arbWEN                     : out std_logic;  -- dcache write request
    arbWait                    : in  std_logic;  -- dcache must wait if 1
    arbAddr                    : out std_logic_vector(31 downto 0);  -- dcache address being read
    arbReadData                : in  std_logic_vector(31 downto 0);  -- dcache data to be read
    arbWriteData               : out std_logic_vector(31 downto 0);  -- dcache data to be written
    -- dcache side (sets 1 and 2)
    s1_tag, s2_tag             : out std_logic_vector(24 downto 0);
    s1_tagOut, s2_tagOut       : in  std_logic_vector(24 downto 0);
    s1_index, s2_index         : out std_logic_vector(3 downto 0);
    s1_wdat, s2_wdat           : out std_logic_vector(63 downto 0);  -- write data to be written on datWEN
    s1_wDirty, s2_wDirty       : out std_logic;  -- dirty bit to be written on datWEN
    s1_datWEN, s2_datWEN       : out std_logic;
    s1_rdat, s2_rdat           : in  std_logic_vector(63 downto 0);
    s1_rHit, s2_rHit           : in  std_logic;
    s1_rDirty, s2_rDirty       : in  std_logic;
    s1_rRecent, s2_rRecent     : in  std_logic;
    s1_wRecent, s2_wRecent     : out std_logic;
    s1_recentWEN, s2_recentWEN : out std_logic;
    halt_out                   : out std_logic
    );
  end component;



  
  component dcacheSet port(
    clk, nrst : in std_logic;
    tag_in    : in std_logic_vector(24 downto 0);
    data_in   : in std_logic_vector(63 downto 0);
    index_in  : in std_logic_vector(3 downto 0);


    recent_in : in std_logic;
    dirty_in  : in std_logic;

    recent_wen : in std_logic;
    data_wen   : in std_logic;

    data_out : out std_logic_vector(63 downto 0);
    tag_out  : out std_logic_vector(24 downto 0);
    hit      : out std_logic;
    dirty    : out std_logic;
    recent   : out std_logic);
  end component;

  signal s1Cntrl, s2Cntrl : dcacheSetCntrl;
  
begin

  cntrl_c : dcache_ctrl port map (
    clk           => clk,
    nReset        => nReset,
    halt          => halt,
    dmemREN       => dMemRead,
    dmemWEN       => dMemWrite,
    dmemAddr      => dMemAddr,
    dmemWriteData => dMemDataWrite,
    dmemReadData  => dMemDataRead,
    dmemWait      => dMemWait,
    arbREN        => adMemRead,
    arbWEN        => adMemWrite,
    arbWait       => adMemWait,
    arbAddr       => adMemAddr,
    arbReadData   => adMemDataRead,
    arbWriteData  => adMemDataWrite,
    s1_tag        => s1Cntrl.tag_in,
    s1_tagOut     => s1Cntrl.tag_out,
    s1_index      => s1Cntrl.index_in,
    s1_wdat       => s1Cntrl.data_in,
    s1_rdat       => s1Cntrl.data_out,
    s1_wDirty     => s1Cntrl.dirty_in,
    s1_rDirty     => s1Cntrl.dirty,
    s1_wRecent    => s1Cntrl.recent_in,
    s1_rRecent    => s1Cntrl.recent,
    s1_datWEN     => s1Cntrl.data_wen,
    s1_recentWEN  => s1Cntrl.recent_wen,
    s1_rHit       => s1Cntrl.hit,

    s2_tag       => s2Cntrl.tag_in,
    s2_tagOut    => s2Cntrl.tag_out,
    s2_index     => s2Cntrl.index_in,
    s2_wdat      => s2Cntrl.data_in,
    s2_rdat      => s2Cntrl.data_out,
    s2_wDirty    => s2Cntrl.dirty_in,
    s2_rDirty    => s2Cntrl.dirty,
    s2_wRecent   => s2Cntrl.recent_in,
    s2_rRecent   => s2Cntrl.recent,
    s2_datWEN    => s2Cntrl.data_wen,
    s2_recentWEN => s2Cntrl.recent_wen,
    s2_rHit      => s2Cntrl.hit,
    halt_out     => halt_out);

  s1Cntrl.clk  <= clk;
  s2Cntrl.clk  <= clk;
  s1Cntrl.nrst <= nReset;
  s2Cntrl.nrst <= nReset;

  s1_c : dcacheSet port map (
    clk      => s1Cntrl.clk,
    nrst     => s1Cntrl.nrst,
    tag_in   => s1Cntrl.tag_in,
    data_in  => s1Cntrl.data_in,
    index_in => s1Cntrl.index_in,


    recent_in  => s1Cntrl.recent_in,
    dirty_in   => s1Cntrl.dirty_in,
    recent_wen => s1Cntrl.recent_wen,
    data_wen   => s1Cntrl.data_wen,

    data_out => s1Cntrl.data_out,
    tag_out  => s1Cntrl.tag_out,
    hit      => s1Cntrl.hit,
    dirty    => s1Cntrl.dirty,
    recent   => s1Cntrl.recent);

  s2_c : dcacheSet port map (
    clk      => s2Cntrl.clk,
    nrst     => s2Cntrl.nrst,
    tag_in   => s2Cntrl.tag_in,
    data_in  => s2Cntrl.data_in,
    index_in => s2Cntrl.index_in,


    recent_in  => s2Cntrl.recent_in,
    dirty_in   => s2Cntrl.dirty_in,
    recent_wen => s2Cntrl.recent_wen,
    data_wen   => s2Cntrl.data_wen,

    data_out => s2Cntrl.data_out,
    tag_out  => s2Cntrl.tag_out,
    hit      => s2Cntrl.hit,
    dirty    => s2Cntrl.dirty,
    recent   => s2Cntrl.recent);

end struct;
